package com.hermit.file.controller.admin;

import com.hermit.server.dto.FileDto;
import com.hermit.server.dto.ResponseDto;
import com.hermit.server.enums.FileUseEnum;
import com.hermit.server.service.FileService;
import com.hermit.server.util.Base64ToMultipartFile;
import com.hermit.server.util.UUidUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.UUID;


@RequestMapping("/admin")
@RestController
public class UploadController {

    //定义一个测试日志
    private static final Logger LOG = LoggerFactory.getLogger(UploadController.class);
    //日志业务名称
    public static final String BUSINESS_NAME = "文件上传";
    @Value("${file.domain}")
    private String FILE_DOMAIN;
    @Value("${file.path}")
    private String FILE_PATH;

    @Resource
    private FileService fileService;
    /**上传文件方法*/
    @RequestMapping("/upload")
    public ResponseDto upload(@RequestBody FileDto fileDto) throws Exception {
        //输出日志
        LOG.info("上传文件开始");
//        LOG.info(shard.getOriginalFilename());
//        LOG.info(String.valueOf(shard.getSize()));
        String use = fileDto.getUse();
        String key = fileDto.getKey();
        String suffix = fileDto.getSuffix();
        String shardBase64 = fileDto.getShard(); //String类型
        MultipartFile shard = Base64ToMultipartFile.base64ToMultipart(shardBase64);

        //保存文件到本地
        FileUseEnum fileUseEnum = FileUseEnum.getByCode(use);



        //如果文件不存在，则创建文件夹
        String dir = fileUseEnum.name().toLowerCase();
        File fullDir = new File(FILE_PATH + dir);
        if(!fullDir.exists()){
            fullDir.mkdir();
        }


//        String fileName = shard.getOriginalFilename(); //文件名 原始 对应name
//        String suffix = fileName.substring(fileName.lastIndexOf(".")+1).toLowerCase(); //后缀
//        String path = "teacher/" + key + "." + suffix; //文件路径 相对

        String path = new StringBuffer(dir)
                .append(File.separator)
                .append(key)
                .append(".")
                .append(suffix)
                .toString(); //文件路径 相对

        String localPath = new StringBuffer(path)
                .append(".yf")
                .append(fileDto.getShardIndex())
                .toString(); //文件路径 相对

        String fillPath = FILE_PATH + localPath;   //绝对路径
        File dest = new File(fillPath);
        shard.transferTo(dest);
        LOG.info(dest.getAbsolutePath());


        //保存文件到数据库
        LOG.info("保存文件记录开始");
        /**拿
         * 文件id           key
         * 文件名 name      fileName = file.getOriginalFilename()
         * 文件路径 path    "teacher/"+key+"-"+fileName
         * 文件后缀 suffix  fileName.subString(fileName.lastIndexOf(".")+1)
         * 文件大小 size    Math.toIntExact(file.getSize())
         * 文件使用 use
         * 创建时间 created_at
         * 修改时间 update_at
         * */
        fileDto.setPath(path);
        fileService.save(fileDto);


        ResponseDto responseDto = new ResponseDto();
        //返回全路径
        fileDto.setPath(FILE_DOMAIN+path);
        responseDto.setContent(fileDto);

        //如果是最后一个分片 则合并分片
        if(fileDto.getShardIndex().equals(fileDto.getShardTotal())){
            this.merge(fileDto);
        }
        return responseDto;
    }

//    @RequestMapping("/upload")
//    public ResponseDto upload(@RequestParam MultipartFile file,String use) throws IOException {
//        //输出日志
//        LOG.info("上传文件开始:{}", file);
//        LOG.info(file.getOriginalFilename());
//        LOG.info(String.valueOf(file.getSize()));
//
//
//        //保存文件到本地
//        FileUseEnum fileUseEnum = FileUseEnum.getByCode(use);
//
//        String dir = fileUseEnum.name().toLowerCase();
//        File fullDir = new File(FILE_PATH + dir);
//        if(!fullDir.exists()){
//            fullDir.mkdir();
//        }
//
//        String key = UUidUtil.getShortUuid();
//        String fileName = file.getOriginalFilename(); //文件名 原始 对应name
//        String suffix = fileName.substring(fileName.lastIndexOf(".")+1).toLowerCase(); //后缀
////        String path = "teacher/" + key + "." + suffix; //文件路径 相对
//        String path = dir + File.separator + key + "." + suffix; //文件路径 相对
//        String fillPath = FILE_PATH + path;   //绝对路径
//        File dest = new File(fillPath);
//        file.transferTo(dest);
//        LOG.info(dest.getAbsolutePath());
//
//
//        //保存文件到数据库
//        LOG.info("保存文件记录开始");
//        /**拿
//         * 文件id           key
//         * 文件名 name      fileName = file.getOriginalFilename()
//         * 文件路径 path    "teacher/"+key+"-"+fileName
//         * 文件后缀 suffix  fileName.subString(fileName.lastIndexOf(".")+1)
//         * 文件大小 size    Math.toIntExact(file.getSize())
//         * 文件使用 use
//         * 创建时间 created_at
//         * 修改时间 update_at
//         * */
//        FileDto fileDto = new FileDto();
//        fileDto.setPath(path);
//        fileDto.setName(fileName);
//        fileDto.setSuffix(suffix);
//        fileDto.setSize(Math.toIntExact(file.getSize()));
//        fileDto.setUse(use);
//        fileService.save(fileDto);
//
//
//        ResponseDto responseDto = new ResponseDto();
//        //返回全路径
//        fileDto.setPath(FILE_DOMAIN+path);
//        responseDto.setContent(fileDto);
//        return responseDto;
//    }

    /**合并断点续传*/
    public void merge(FileDto fileDto) throws Exception{
        LOG.info("合并分片开始");
        String path = fileDto.getPath();
        path = path.replace(FILE_DOMAIN,"");
        //最终输出文件
        File newFile = new File(FILE_PATH+ path);
        Integer shardTotal = fileDto.getShardTotal();
        //定义输出流  true为往文件里面追加
        FileOutputStream fileOutputStream = new FileOutputStream(newFile,true);
        //输入流  分片文件
        FileInputStream fileInputStream =null;

        byte[] byt = new byte[10*1024*1024];
        int len;
        try{

            for(int i=0;i<shardTotal;i++){
                fileInputStream = new FileInputStream(new File(FILE_PATH + path + ".yf" + (i+1) ));
                while ((len = fileInputStream.read(byt)) != -1){
                    fileOutputStream.write(byt,0,len);
                }
            }


        }catch (IOException e){
            LOG.error("分片合并异常",e);
        }finally {
            try{
                if(fileInputStream != null){
                    fileInputStream.close();
                }
                fileOutputStream.close();
                LOG.info("IO流关闭");
            }catch (Exception e ){
                LOG.error("IO流关闭异常",e);
            }
        }
        LOG.info("合并分片结束");

        //垃圾回收
        System.gc();
        Thread.sleep(100);

        //删除分片
        LOG.info("删除分片开始");
        for(int i =0;i<shardTotal;i++){
            String filePath = FILE_PATH + path + ".yf" + (i+1);
            File file = new File(filePath);
            boolean result = file.delete();
            LOG.info("删除{}{}",filePath,result? "成功":"失败");
        }
        LOG.info("删除分片结束");
    }

    /**检查分片*/
    @GetMapping("/check/{key}")
    public ResponseDto check(@PathVariable String key){
        LOG.info("检查上传分片开始：{}" ,key);
        ResponseDto responseDto = new ResponseDto();
        FileDto fileDto = fileService.findByKey(key);
        if(fileDto != null){
            fileDto.setPath(FILE_DOMAIN + fileDto.getPath());
        }
        responseDto.setContent(fileDto);
        return responseDto;
    }


}
